package com.contexttree.filereader;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import javax.swing.JTextArea;

import com.contexttree.utils.FilePrinter;
import com.contexttree.utils.Printer;

/**
 * This class manage all the operation on CSV file
 * Politecnico di Milano 2012
 * @author Paolo Barbaglia
 * @author Filippo Ferrari
 *
 */
public class ReadCsvFile {
	
	public static ArrayList<String> read(String filename) {
		ArrayList<String> stringList = new ArrayList<String>();
		try{
			FileInputStream fstream = new FileInputStream(filename);
	        DataInputStream in = new DataInputStream(fstream);
	        BufferedReader br = new BufferedReader(new InputStreamReader(in));
	        String strLine;
	        
	        while ((strLine = br.readLine()) != null){
	        	stringList.add(strLine);

	        }	        
	        in.close();
	        
	    }catch (Exception e){
	        System.err.println("Errore: " + e.getMessage());
	    }
		return stringList;	
	}
	
	public static int countId(ArrayList<String> csvFile){
		int numId = 0;
		int headerLength = csvFile.get(0).split("\\,").length;
		String[][] recordsSplitted = new String [csvFile.size()][headerLength];
		
		
		for(int i=0; i<csvFile.size(); i++){ //Scandisco array csvfile e splitto una riga per volta
	    	
	    	recordsSplitted[i] = csvFile.get(i).split("\\,");
		}

		for(int i=1; i<csvFile.size(); i++){  //scandisco recordsSplitted...
			int var = 0;
			for (int j=i-1; j>0; j--){   //e partendo dalla posizione corrente valuto se nelle stringhe precedenti era presente uno stesso id
				if (recordsSplitted[i][0].equals(recordsSplitted[j][0])) var = 1; //se trovo id uguale trai precedenti, var cambia valore
			}
		if (var==0) numId++; //se var nn ha cambiato valore abbiamo un nuovo id, quindi nuovo records 
		
		}
		return numId;
	}
	
	/**
	 * This method receive the ArrayList<String> csvFile and the int numRecords and returns the String [][] checkRecords
	 * that is a matrix. What makes a line different from another is the value of the field ID that characterize a line.
	 * If a field contains more then one value for each Id, these value will be separated with " ". The first line will
	 * contains the headers. 
	 * Politecnico di Milano 2012
	 * @param csvFile
	 * @param numRecords
	 * @return recordsOkSplitted
	 */
	public static String[][] checkRecords(ArrayList<String> csvFile, int numRecords){
		//Variables init;
	    int headerLength = csvFile.get(0).split("\\,").length;   
	    String[][] recordsSplitted = new String [csvFile.size()][headerLength];
	    String[][] recordsOkSplitted = new String [numRecords+1][headerLength]; //numRecords +1 , poich� conterr� anche i campi
	    
	    for (int j=0; j<=numRecords; j++){        //inizializzo recordsOkSplitted
	    	for (int i=0; i<headerLength; i++){
	    		recordsOkSplitted[j][i] = "";
	    	}	    	
	    }
	    
	    for (int j=0; j<csvFile.size(); j++){        //inizializzo recordsSplitted
	    	for (int i=0; i<headerLength; i++){
	    		recordsSplitted[j][i] = "";
	    	}	    	
	    }
	    
	    for(int i=0; i<csvFile.size(); i++){ //Scandisco array csvfile e splitto una riga per volta
	    	
	    	recordsSplitted[i] = csvFile.get(i).split("\\,");
	    	
	    }
	    
	    for(int j=0; j<csvFile.size(); j++){ //Scandisci recordsSplitted
    		
	    	int var = 0;	    	
	    	
	    	for (int t=0; t<=numRecords; t++){//scandisci recordsOkSplitted
	    			
	    		if(recordsSplitted[j][0].equals(recordsOkSplitted[t][0])){ //se si tratta di un id uguale
	    		
	    			var = 1;
	    			for (int z=1; z<headerLength; z++){ //aggiungi tutti i valori nuovi ai campi
	    				
	    				if ((!recordsOkSplitted[t][z].contains(recordsSplitted[j][z])) && (recordsSplitted[j][z].compareTo("\n")) !=0){ //se il campo � nuovo ed � diverso dal carattere "a capo"
	    					
	    					if (recordsOkSplitted[t][z].compareTo("")!=0)   // se erano presenti altre stringhe
	    						recordsOkSplitted[t][z] += " " + recordsSplitted[j][z];
	    					else
	    						recordsOkSplitted[t][z] = recordsSplitted[j][z]; //se � la prima stringa
	    				}
	    			}
	    		}
	    	}
	    	
	    	if (var == 0){//se scandendo recordsOkSplitted non ho trovato corrispondenza aggiungo la stringa
	    				//con tutti i campi al primo posto libero di recordsOkSplitted
	    					
	    		for (int k=0; k<=numRecords; k++){
	    			
	    			if (recordsOkSplitted[k][0]==""){  //quando trovo la prima riga vuota (disponibile)
	    				
	    				for (int z=0; z<headerLength; z++){  // riempio con tutti i campi
	    					
	    					if (recordsSplitted[j][z].compareTo("\n") !=0 ) //se il campo recordsSplitted[j][z] non contiene il carattere "a capo"
	    						recordsOkSplitted[k][z] = recordsSplitted[j][z];  
	    							//altrimenti recordsOkSplitted[k][z] mantiene il valore che ha gi�, ossia "" 
	    				}	
	    			k = numRecords +1;   //mi permette di uscire dal ciclo
	    			}	
	    		}
	    	}	
	    }
	    return recordsOkSplitted;
	}
	
	public static void print(String[][] recordsOkSplitted, ArrayList<String> csvFile,int numRecords, JTextArea txtLogPanel){
		int headerLength = csvFile.get(0).split("\\,").length;
		
		for (int j=1; j<=numRecords; j++){        //Stampo recordsOkSplitted
    		for (int i=0; i<headerLength; i++){
    			if (recordsOkSplitted[j][i].compareTo("")!=0){
    				if (i==(headerLength-1))
    					if(txtLogPanel==null){
    						Printer.print(recordsOkSplitted[0][i] + ": " + recordsOkSplitted[j][i]);
    					} else {
    						txtLogPanel.append(recordsOkSplitted[0][i] + ": " + recordsOkSplitted[j][i] + "\n");
    					}
    				else{
    					if(txtLogPanel==null){
        					Printer.print(recordsOkSplitted[0][i] + ": " + recordsOkSplitted[j][i] + ", ");
    					} else {
        					txtLogPanel.append(recordsOkSplitted[0][i] + ": " + recordsOkSplitted[j][i] + ", ");
    					}
    				}
    			}
    		}	    	
    	}
	}
		
	public static String getHeader(ArrayList<String> csvFile){
		return csvFile.get(0);
	}
	
	/**
	 * This method receive the ArrayList<String> arrayListPositive and returns it with the new field "Status=POSITIVE"
	 * Politecnico di Milano 2012
	 * @param arrayListPositive
	 * @return arrayListPositive
	 */
	
	public static ArrayList<String> addFieldPositive (ArrayList<String> arrayListPositive){
		
		arrayListPositive.set(0, arrayListPositive.get(0) + ",positive");
		
		for ( int i=1; i<arrayListPositive.size(); i++) {
			arrayListPositive.set(i, arrayListPositive.get(i) + ",positive");
		}
		
	return arrayListPositive;
	}
	
	/**
	 * This method receive the ArrayList<String> arrayListUnlabeled and returns it with the new field "Status=UNLABELED"
	 * Politecnico di Milano 2012
	 * @param arrayListUnlabeled
	 * @return arrayListUnlabeled
	 */
	public static ArrayList<String> addFieldUnlabeled (ArrayList<String> arrayListUnlabeled){
		
		arrayListUnlabeled.set(0, arrayListUnlabeled.get(0) + ",positive");
		
		for ( int i=1; i<arrayListUnlabeled.size(); i++) {
			arrayListUnlabeled.set(i, arrayListUnlabeled.get(i) + ",unlabeled");
		}
		
	return arrayListUnlabeled;
	}

	/**
	 * This method receive the ArrayList<String> arrayListPositive and the ArrayList<String> arrayListUnlabeled
	 * and returns the ArrayList<String> concatenated that is the union of the ArrayLists received.
	 * Politecnico di Milano 2012
	 * @param arrayListPositive
	 * @param arrayListUnlabeled
	 * @return concatenated
	 */
	
	public static ArrayList<String> concatenate (ArrayList<String> arrayListPositive, ArrayList<String> arrayListUnlabeled) {
		ArrayList<String> concatenated = new ArrayList<String>();
		
		for ( int i=0; i<arrayListPositive.size(); i++) {
			concatenated.add(arrayListPositive.get(i));  //Inserisce all'ArrayList concatenated "arrayListPositive" compreso l'header
		}	
    
		for ( int i=1; i<arrayListUnlabeled.size(); i++) {    //Inserisce in coda a concatenated "arrayListUnlabeled"
			concatenated.add(arrayListUnlabeled.get(i)); //il contatore del metodo get() parte da i+1 poich� elimina l'header
		}
		
    return concatenated;
	}
	
	/**
	 * This method receive the String [][] records and returns it modifing the Ids in ascending order starting from 1.
	 * Anyway the UNLABELED matches comes after the POSITIVE matches.
	 * Politecnico di Milano 2012
	 * @param records
	 * @return records
	 */
	
	public static String[][] arrangeId (String[][] records){
		
		for (int i=1; i<records.length; i++){ //la prima riga contiene l'header, la numerazione parte da 1
			records[i][0]=String.valueOf(i);		
		}
		
	return records;
	} 
	
	/**
	 * This method receive the String [][] records and returns the String [][] recordsWithoutHeaders that it similar to records, but it
	 * eliminates the first row and specify the field before every value.
	 * Politecnico di Milano 2012
	 * @param records
	 * @return recordsWithoutHeader
	 */
	
	public static String [][] eliminateHeaders(String[][] records){
		int headerLength = records[0].length;
		int numRecords = (records.length - 1);
		String[][] recordsWithoutHeader = new String [numRecords][headerLength];
		
		for (int j=0; j<numRecords; j++){        //inizializzo recordsWithoutHeaders
	    	for (int i=0; i<headerLength; i++){
	    		recordsWithoutHeader[j][i] = "";
	    	}
		}
		
		for (int j=0; j<numRecords; j++){        
    		for (int i=0; i<headerLength; i++){
    				recordsWithoutHeader[j][i] = records[0][i] + ":" + records[j+1][i];
    		}
    	}	    	
    	
		return recordsWithoutHeader;
	}
	
	/**
	 * This method receive the String [][] recordsWithoutHeader and returns the String [][] converted that is the the structure riceived, but
	 * every association field=value is converted to number. The method launch FilePrinter.printDictionary and FilePrinter.printTableConverted.
	 * Politecnico di Milano 2012
	 * @param recordsWithoutHeader
	 * @return converted
	 */
	
	public static String[][] convertToNumber(String[][] recordsWithoutHeader, String FolderPath, String filename){
		int headerLength = recordsWithoutHeader[0].length;
		int numRecords = recordsWithoutHeader.length;
		int maxDimension = numRecords*headerLength;
		String [][] converted = new String[numRecords][headerLength];
		String [] association = new String[maxDimension]; //indicher� l'associazione tra stringa e valore 
		
		
		for (int j=0; j<numRecords; j++){        //inizializzo converted
	    	for (int i=0; i<headerLength; i++){
	    		converted[j][i] = "";
	    	}
		}
		
		for (int j=0; j<maxDimension; j++){        //inizializzo association
			association[j] = "";
	    }
		
		for (int j=0; j<numRecords; j++){
	    	for (int i=0; i<headerLength; i++){
	    		int numString = recordsWithoutHeader[j][i].split(" ").length; //numString indica il numero di valori contenuti
	    		String[] everyValue = new String [numString]; //l'array everyValue contiene tutti i valori
	    		everyValue = recordsWithoutHeader[j][i].split(" ");
	    		String[] field = new String[2];
	    		field = recordsWithoutHeader[j][i].split(":", 2); //la stringa field[0] conterr� solo il campo
	    		
	    		for (int m=0; m<maxDimension; m++){ //N.B. in questo blocco tratto separatamente everyValue[0] poich� esso contiene gi� il campo; //scorro association
    				if (!association[m].equals("")){ //se association[m] non � vuota
    					if (association[m].equals(everyValue[0])){
    						if (!converted[j][i].equals("")){
    							converted[j][i]=converted[j][i]+" "+String.valueOf(m+1);
    							m=maxDimension;  //mi permette di uscire dal ciclo
    						}
    						else{
    							converted[j][i]=String.valueOf(m+1);
    							m=maxDimension;  //mi permette di uscire dal ciclo
    						}
    					}
    				}
    				else{		//se association[m] � vuota
    					association[m]=(everyValue[0]);  //crea una nuova associazione
    					if (!converted[j][i].equals("")){
							converted[j][i]=converted[j][i]+" "+String.valueOf(m+1);
							m=maxDimension;  //mi permette di uscire dal ciclo
						}
						else{
							converted[j][i]=String.valueOf(m+1);
							m=maxDimension;  //mi permette di uscire dal ciclo
						}
    				}
	    		}	    			
	    		
	    		for (int k=1; k<numString; k++){ //scorro everyString
	    			for (int m=0; m<maxDimension; m++){ //scorro association
	    				if (!association[m].equals("")){ //se association[m] non � vuota
	    					if (association[m].equals(field[0]+":"+everyValue[k])){
	    						if (!converted[j][i].equals("")){
	    							converted[j][i]=converted[j][i]+" "+String.valueOf(m+1);
	    							m=maxDimension;  //mi permette di uscire dal ciclo
	    						}
	    						else{
	    							converted[j][i]=String.valueOf(m+1);
	    							m=maxDimension;  //mi permette di uscire dal ciclo
	    						}
	    					}
	    				}
	    				else{		//se association[m] � vuota
	    					association[m]=(field[0]+":"+everyValue[k]);  //crea una nuova associazione
	    					if (!converted[j][i].equals("")){
    							converted[j][i]=converted[j][i]+" "+String.valueOf(m+1);
    							m=maxDimension;  //mi permette di uscire dal ciclo
    						}
    						else{
    							converted[j][i]=String.valueOf(m+1);
    							m=maxDimension;  //mi permette di uscire dal ciclo
    						}
	    				}
	    			}	
	    		} 	    		
	    	}
		}
		
		FilePrinter.printDictionary(filename + "All" + ".diz",FolderPath,association);
		FilePrinter.printTableConverted(filename + "All" + ".dat",FolderPath,converted);
		
		FilePrinter.printDictionary(filename + "All" + ".diz","./",association);
		FilePrinter.printTableConverted(filename + "All" + ".dat","./",converted);
		return converted;
		
	}

}       		